/*******************************************************************************
 * Copyright (c) 2009 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Ali Ok (www.aliok.info) - initial API and implementation
 *******************************************************************************/
package org.eclipse.team.internal.search;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.compare.CompareEditorInput;
import org.eclipse.compare.CompareUI;
import org.eclipse.compare.ITypedElement;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.util.OpenStrategy;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.search.ui.ISearchResult;
import org.eclipse.search.ui.ISearchResultListener;
import org.eclipse.search.ui.ISearchResultPage;
import org.eclipse.search.ui.ISearchResultViewPart;
import org.eclipse.search.ui.SearchResultEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.team.core.history.IFileRevision;
import org.eclipse.team.internal.core.history.LocalFileRevision;
import org.eclipse.team.internal.ui.history.CompareFileRevisionEditorInput;
import org.eclipse.team.internal.ui.history.FileRevisionTypedElement;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.IPageSite;

public class SearchResultPage implements ISearchResultPage {

	private String id;
	private Composite control;
	private IPageSite site;
	private TreeViewer viewer;

	public String getID() {
		return id;
	}

	public String getLabel() {
		return "ViewLabel";
	}

	public Object getUIState() {
		return null;
	}

	public void restoreState(IMemento memento) {

	}

	public void saveState(IMemento memento) {
		// TODO Auto-generated method stub

	}

	public void setID(String id) {
		this.id = id;
	}

	public void setInput(ISearchResult search, Object uiState) {
		viewer.setInput(search);
	}

	public void setViewPart(ISearchResultViewPart part) {

	}

	public IPageSite getSite() {
		return site;
	}

	public void init(IPageSite site) throws PartInitException {
		this.site = site;
	}

	public void createControl(Composite parent) {
		control = new Composite(parent, SWT.NONE);
		control.setLayout(new FillLayout());
		viewer = new TreeViewer(control, SWT.NONE);

		viewer.setContentProvider(new ITreeContentProvider() {

			SearchResult result;

			Map<String, ArrayList<IFileRevision>> internalRepresentation = new HashMap<String, ArrayList<IFileRevision>>();

			public void inputChanged(final Viewer viewer, Object oldInput,
					Object newInput) {
				if (newInput != oldInput) {
					if (oldInput != null) {
						((SearchResult) oldInput).removeAllListeners();
					}
					result = (SearchResult) newInput;
					if (result != null)
						result.addListener(new ISearchResultListener() {
							public void searchResultChanged(SearchResultEvent e) {
								Display.getDefault().asyncExec(new Runnable() {
									public void run() {
										viewer.refresh();
									}
								});
							}
						});
				}
				viewer.refresh();
			}

			public void dispose() {
				// TODO Auto-generated method stub
			}

			private void computeInternalRepresentation() {
				internalRepresentation.clear();
				if (result == null) {
					return;
				}
				ArrayList<IFileRevision> revisions = result.getResult();
				for (int i = 0; i < revisions.size(); i++) {
					String comment = revisions.get(i).getComment();
					if (!internalRepresentation.containsKey(comment)) {
						internalRepresentation.put(comment,
								new ArrayList<IFileRevision>());
					}
					internalRepresentation.get(comment).add(revisions.get(i));
				}
			}

			public Object[] getElements(Object inputElement) {
				// TODO: this is highly inefficient
				computeInternalRepresentation();
				return internalRepresentation.keySet().toArray();
			}

			public boolean hasChildren(Object element) {
				// root element
				if (element == result) {
					return result.getResult().size() > 0;
				}
				if (element instanceof String) {
					return true;
				}
				return false;
			}

			public Object getParent(Object element) {
				// TODO Auto-generated method stub
				return null;
			}

			public Object[] getChildren(Object parentElement) {
				if (parentElement instanceof String
						&& internalRepresentation.containsKey(parentElement)) {
					return internalRepresentation.get(parentElement).toArray();
				}
				return new Object[0];
			}
		});
		viewer.setLabelProvider(new ILabelProvider() {

			public void removeListener(ILabelProviderListener listener) {
				// TODO Auto-generated method stub

			}

			public boolean isLabelProperty(Object element, String property) {
				// TODO Auto-generated method stub
				return false;
			}

			public void dispose() {
				// TODO Auto-generated method stub

			}

			public void addListener(ILabelProviderListener listener) {
				// TODO Auto-generated method stub

			}

			public String getText(Object element) {
				if (element instanceof String) {
					return (String) element;
				}
				if (element instanceof IFileRevision) {
					IFileRevision fileRevision = (IFileRevision) element;
					return fileRevision.getName() + " "
							+ fileRevision.getContentIdentifier();
				}
				return "unrecognized!";
			}

			public Image getImage(Object element) {
				// TODO Auto-generated method stub
				return null;
			}
		});
		viewer.addDoubleClickListener(new IDoubleClickListener() {

			public void doubleClick(DoubleClickEvent event) {
				ISelection s = event.getSelection();
				if (!(s instanceof IStructuredSelection)) {
					return;
				}
				IStructuredSelection ss = (IStructuredSelection) s;
				Object item = ss.getFirstElement();
				if (!(item instanceof IFileRevision)) {
					return;
				}
				IFileRevision current = (IFileRevision) item;
				IFileRevision previous = null;
				Object input = viewer.getInput();
				if (input instanceof SearchResult) {
					previous = ((SearchResult) input)
							.getPreviousFileRevision(current);
				}
				openCompareEditor(previous, current);
			}

			// based on org.eclipse.team.ui
			private void openCompareEditor(IFileRevision previous,
					IFileRevision current) {
				if (previous == null || current == null) {
					return;
				}
				ITypedElement left = new FileRevisionTypedElement(previous,
						getLocalEncoding(previous));
				ITypedElement right = new FileRevisionTypedElement(current,
						getLocalEncoding(current));
				openInCompare(left, right);
			}

			private void openInCompare(ITypedElement left, ITypedElement right) {
				CompareEditorInput input = createCompareEditorInput(left,
						right, PlatformUI.getWorkbench()
								.getActiveWorkbenchWindow().getActivePage());
				CompareUI.openCompareEditor(input, OpenStrategy
						.activateOnOpen());
			}

			private String getLocalEncoding(IFileRevision revision) {
				IResource resource = getResource(revision);
				if (resource instanceof IFile) {
					IFile file = (IFile) resource;
					try {
						return file.getCharset();
					} catch (CoreException e) {
						// TODO: handle this
					}
				}
				return null;
			}

			protected CompareFileRevisionEditorInput createCompareEditorInput(
					ITypedElement left, ITypedElement right, IWorkbenchPage page) {
				return new CompareFileRevisionEditorInput(left, right, page);
			}

			private IResource getResource(IFileRevision revision) {
				if (revision instanceof LocalFileRevision) {
					LocalFileRevision local = (LocalFileRevision) revision;
					return local.getFile();
				}
				return null;
			}

		});
	}

	public void dispose() {

	}

	public Control getControl() {
		return control;
	}

	public void setActionBars(IActionBars actionBars) {
		// TODO Auto-generated method stub

	}

	public void setFocus() {
		// TODO Auto-generated method stub

	}

}
